/*      */ package com.zimbra.cs.index.elasticsearch;
/*      */ 
/*      */ import com.google.common.base.Joiner;
/*      */ import com.google.common.collect.Lists;
/*      */ import com.zimbra.common.localconfig.KnownKey;
/*      */ import com.zimbra.common.localconfig.LC;
/*      */ import com.zimbra.common.util.Log;
/*      */ import com.zimbra.common.util.ZimbraLog;
/*      */ import com.zimbra.cs.index.BrowseTerm;
/*      */ import com.zimbra.cs.index.IndexDocument;
/*      */ import com.zimbra.cs.index.IndexStore;
/*      */ import com.zimbra.cs.index.IndexStore.Factory;
/*      */ import com.zimbra.cs.index.Indexer;
/*      */ import com.zimbra.cs.index.LuceneFields.IndexField;
/*      */ import com.zimbra.cs.index.ZimbraAnalyzer;
/*      */ import com.zimbra.cs.index.ZimbraIndexDocumentID;
/*      */ import com.zimbra.cs.index.ZimbraIndexReader;
/*      */ import com.zimbra.cs.index.ZimbraIndexReader.TermFieldEnumeration;
/*      */ import com.zimbra.cs.index.ZimbraIndexSearcher;
/*      */ import com.zimbra.cs.index.ZimbraScoreDoc;
/*      */ import com.zimbra.cs.index.ZimbraTermsFilter;
/*      */ import com.zimbra.cs.index.ZimbraTopDocs;
/*      */ import com.zimbra.cs.index.ZimbraTopFieldDocs;
/*      */ import com.zimbra.cs.mailbox.Folder;
/*      */ import com.zimbra.cs.mailbox.MailItem;
/*      */ import com.zimbra.cs.mailbox.Mailbox;
/*      */ import java.io.BufferedReader;
/*      */ import java.io.IOException;
/*      */ import java.io.PrintStream;
/*      */ import java.io.Reader;
/*      */ import java.io.StringReader;
/*      */ import java.util.Collections;
/*      */ import java.util.Comparator;
/*      */ import java.util.Iterator;
/*      */ import java.util.List;
/*      */ import java.util.NoSuchElementException;
/*      */ import java.util.Queue;
/*      */ import org.apache.commons.httpclient.HttpException;
/*      */ import org.apache.commons.httpclient.HttpMethod;
/*      */ import org.apache.commons.httpclient.NameValuePair;
/*      */ import org.apache.commons.httpclient.methods.DeleteMethod;
/*      */ import org.apache.commons.httpclient.methods.GetMethod;
/*      */ import org.apache.commons.httpclient.methods.PostMethod;
/*      */ import org.apache.commons.httpclient.methods.PutMethod;
/*      */ import org.apache.commons.httpclient.methods.StringRequestEntity;
/*      */ import org.apache.lucene.analysis.Analyzer;
/*      */ import org.apache.lucene.analysis.TokenStream;
/*      */ import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
/*      */ import org.apache.lucene.document.Document;
/*      */ import org.apache.lucene.document.Field;
/*      */ import org.apache.lucene.document.Field.Index;
/*      */ import org.apache.lucene.document.Field.Store;
/*      */ import org.apache.lucene.document.Fieldable;
/*      */ import org.apache.lucene.index.Term;
/*      */ import org.apache.lucene.search.BooleanClause;
/*      */ import org.apache.lucene.search.BooleanClause.Occur;
/*      */ import org.apache.lucene.search.BooleanQuery;
/*      */ import org.apache.lucene.search.MultiPhraseQuery;
/*      */ import org.apache.lucene.search.MultiTermQuery;
/*      */ import org.apache.lucene.search.PhraseQuery;
/*      */ import org.apache.lucene.search.PrefixQuery;
/*      */ import org.apache.lucene.search.Query;
/*      */ import org.apache.lucene.search.Sort;
/*      */ import org.apache.lucene.search.SortField;
/*      */ import org.apache.lucene.search.TermQuery;
/*      */ import org.apache.lucene.search.TermRangeQuery;
/*      */ import org.apache.lucene.search.WildcardQuery;
/*      */ import org.json.JSONArray;
/*      */ import org.json.JSONException;
/*      */ import org.json.JSONObject;
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ public final class ElasticSearchIndex
/*      */   extends IndexStore
/*      */ {
/*      */   private static final String indexType = "zimbra";
/*      */   private final Mailbox mailbox;
/*      */   private final String key;
/*      */   private final String indexUrl;
/*  102 */   private boolean haveMappingInfo = false;
/*      */   
/*      */   private ElasticSearchIndex(Mailbox mbox) {
/*  105 */     this.mailbox = mbox;
/*  106 */     this.key = this.mailbox.getAccountId();
/*  107 */     this.indexUrl = String.format("%s%s/", new Object[] { LC.zimbra_index_elasticsearch_url_base.value(), this.key });
/*      */   }
/*      */   
/*      */   private void initializeIndex() {
/*  111 */     if (this.haveMappingInfo) {
/*  112 */       return;
/*      */     }
/*  114 */     if (!refreshIndexIfNecessary()) {
/*      */       try {
/*  116 */         ElasticSearchConnector connector = new ElasticSearchConnector();
/*  117 */         JSONObject mappingInfo = createMappingInfo();
/*  118 */         PutMethod putMethod = new PutMethod(ElasticSearchConnector.actualUrl(this.indexUrl));
/*  119 */         putMethod.setRequestEntity(new StringRequestEntity(mappingInfo.toString(), "application/json", "utf-8"));
/*      */         
/*  121 */         int statusCode = connector.executeMethod(putMethod);
/*  122 */         if (statusCode == 200) {
/*  123 */           this.haveMappingInfo = true;
/*  124 */           refreshIndexIfNecessary();
/*      */         } else {
/*  126 */           ZimbraLog.index.error("Problem Setting mapping information for index with key=%s httpstatus=%d", new Object[] { this.key, Integer.valueOf(statusCode) });
/*      */         }
/*      */       }
/*      */       catch (HttpException e) {
/*  130 */         ZimbraLog.index.error("Problem Getting mapping information for index with key=" + this.key, e);
/*      */       } catch (IOException e) {
/*  132 */         ZimbraLog.index.error("Problem Getting mapping information for index with key=" + this.key, e);
/*      */       } catch (JSONException e) {
/*  134 */         ZimbraLog.index.error("Problem Setting mapping information for index with key=" + this.key, e);
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   private boolean refreshIndexIfNecessary()
/*      */   {
/*  144 */     String url = String.format("%s_refresh", new Object[] { this.indexUrl });
/*  145 */     GetMethod method = new GetMethod(ElasticSearchConnector.actualUrl(url));
/*      */     try {
/*  147 */       ElasticSearchConnector connector = new ElasticSearchConnector();
/*  148 */       int statusCode = connector.executeMethod(method);
/*  149 */       if (statusCode == 200)
/*  150 */         return true;
/*  151 */       if (statusCode == 404) {
/*  152 */         ZimbraLog.index.debug("Index not present on %s %d", new Object[] { url, Integer.valueOf(statusCode) });
/*  153 */         return false;
/*      */       }
/*  155 */       ZimbraLog.index.error("Problem refreshing index %s %d", new Object[] { url, Integer.valueOf(statusCode) });
/*      */     } catch (HttpException e) {
/*  157 */       ZimbraLog.index.error("Problem refreshing index %s", url, e);
/*      */     } catch (IOException e) {
/*  159 */       ZimbraLog.index.error("Problem refreshing index %s", url, e);
/*      */     }
/*  161 */     return false;
/*      */   }
/*      */   
/*      */   private JSONObject createMappingInfo() throws JSONException {
/*  165 */     JSONObject topLevel = new JSONObject();
/*  166 */     JSONObject settings = new JSONObject();
/*  167 */     JSONObject mappings = new JSONObject();
/*  168 */     JSONObject zimbra = new JSONObject();
/*  169 */     JSONObject properties = new JSONObject();
/*  170 */     JSONObject source = new JSONObject();
/*  171 */     topLevel.put("settings", settings);
/*  172 */     JSONObject index = new JSONObject();
/*  173 */     settings.put("index", index);
/*  174 */     JSONObject analysis = new JSONObject();
/*  175 */     index.put("analysis", analysis);
/*  176 */     JSONObject analyzer = new JSONObject();
/*  177 */     analysis.put("analyzer", analyzer);
/*  178 */     JSONObject zimbraContent = new JSONObject();
/*  179 */     analyzer.put("zimbrastandard", zimbraContent);
/*      */     
/*      */ 
/*  182 */     zimbraContent.put("tokenizer", "whitespace");
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  192 */     JSONObject emailaddress = new JSONObject();
/*  193 */     analyzer.put("emailaddress", emailaddress);
/*  194 */     emailaddress.put("type", "pattern");
/*  195 */     emailaddress.put("pattern", "(\\s+)|([<>,\\'\\\"]+)|(\\)+)|(\\(+)|(\\]+)|(\\[+)");
/*      */     
/*  197 */     JSONObject contactdata = new JSONObject();
/*  198 */     analyzer.put("contactdata", contactdata);
/*  199 */     contactdata.put("type", "pattern");
/*  200 */     contactdata.put("pattern", "(\\s+)|([<>,\\'\\\"]+)|(\\)+)|(\\(+)|(\\]+)|(\\[+)");
/*  201 */     JSONArray stopwords = new JSONArray();
/*  202 */     stopwords.put(".");
/*  203 */     contactdata.put("stopwords", stopwords);
/*      */     
/*  205 */     topLevel.put("mappings", mappings);
/*  206 */     mappings.put("zimbra", zimbra);
/*  207 */     zimbra.put("_source", source);
/*  208 */     source.put("enabled", false);
/*  209 */     source.put("_all", false);
/*  210 */     zimbra.put("properties", properties);
/*      */     
/*      */ 
/*      */ 
/*  214 */     properties.put("type", new StringFieldProperty(false).analyzed().analyzer("whitespace").asJSON());
/*      */     
/*  216 */     properties.put("l.partname", new StringFieldProperty(true).notAnalyzed().asJSON());
/*      */     
/*  218 */     properties.put("filename", new StringFieldProperty(true).analyzed().analyzer("whitespace").asJSON());
/*      */     
/*  220 */     properties.put("l.size", new FieldProperty("long", true).notAnalyzed().asJSON());
/*  221 */     properties.put("hasAttach", new StringFieldProperty(true).notAnalyzed().asJSON());
/*  222 */     properties.put("hasFlag", new StringFieldProperty(true).notAnalyzed().asJSON());
/*  223 */     properties.put("priority", new StringFieldProperty(true).notAnalyzed().asJSON());
/*  224 */     properties.put("from", new StringFieldProperty(false).analyzed().analyzer("emailaddress").asJSON());
/*      */     
/*  226 */     properties.put("to", new StringFieldProperty(false).analyzed().analyzer("emailaddress").asJSON());
/*      */     
/*  228 */     properties.put("cc", new StringFieldProperty(false).analyzed().analyzer("emailaddress").asJSON());
/*      */     
/*  230 */     properties.put("env_from", new StringFieldProperty(false).analyzed().analyzer("emailaddress").asJSON());
/*      */     
/*  232 */     properties.put("env_to", new StringFieldProperty(false).analyzed().analyzer("emailaddress").asJSON());
/*      */     
/*      */ 
/*      */ 
/*  236 */     properties.put("msg_id", new StringFieldProperty(false).notAnalyzed().asJSON());
/*  237 */     properties.put("l.field", new StringFieldProperty(false).analyzed().analyzer("zimbrastandard").asJSON());
/*      */     
/*  239 */     properties.put("nameSort", new StringFieldProperty(false).notAnalyzed().asJSON());
/*  240 */     properties.put("subject", new StringFieldProperty(false).analyzed().analyzer("zimbrastandard").asJSON());
/*      */     
/*  242 */     properties.put("subjSort", new StringFieldProperty(false).notAnalyzed().asJSON());
/*  243 */     properties.put("l.content", new StringFieldProperty(false).analyzed().analyzer("zimbrastandard").asJSON());
/*      */     
/*      */ 
/*  246 */     properties.put("attachment", new StringFieldProperty(false).analyzed().analyzer("whitespace").asJSON());
/*      */     
/*  248 */     properties.put("l.mbox_blob_id", new FieldProperty("integer", true).notAnalyzed().asJSON());
/*  249 */     properties.put("l.date", new DateFieldProperty(true).notAnalyzed().asJSON());
/*  250 */     properties.put("l.contactData", new StringFieldProperty(false).analyzed().analyzer("contactdata").asJSON());
/*      */     
/*  252 */     properties.put("has", new StringFieldProperty(false).analyzed().analyzer("zimbrastandard").asJSON());
/*      */     
/*  254 */     properties.put("l.version", new StringFieldProperty(true).notAnalyzed().asJSON());
/*  255 */     return topLevel;
/*      */   }
/*      */   
/*      */   private class FieldProperty
/*      */   {
/*      */     private static final String YES = "yes";
/*      */     private static final String NO = "no";
/*      */     private static final String ANALYZED = "analyzed";
/*      */     private static final String NOT_ANALYZED = "not_analyzed";
/*  264 */     private final JSONObject fieldInfo = new JSONObject();
/*      */     
/*      */     public FieldProperty(String type, boolean store) throws JSONException {
/*  267 */       if (type != null) {
/*  268 */         put("type", type);
/*      */       }
/*  270 */       put("store", store ? "yes" : "no");
/*      */     }
/*      */     
/*  273 */     public FieldProperty analyzed() throws JSONException { return index("analyzed"); }
/*      */     
/*      */ 
/*  276 */     public FieldProperty notAnalyzed() throws JSONException { return index("not_analyzed"); }
/*      */     
/*      */     public FieldProperty index(String indexType) throws JSONException {
/*  279 */       put("index", indexType);
/*  280 */       return this;
/*      */     }
/*      */     
/*  283 */     public FieldProperty analyzer(String analyzer) throws JSONException { put("analyzer", analyzer);
/*  284 */       return this;
/*      */     }
/*      */     
/*  287 */     public FieldProperty put(String key, String value) throws JSONException { this.fieldInfo.put(key, value);
/*  288 */       return this;
/*      */     }
/*      */     
/*      */ 
/*  292 */     public JSONObject asJSON() { return this.fieldInfo; }
/*      */   }
/*      */   
/*      */   private class DateFieldProperty extends ElasticSearchIndex.FieldProperty {
/*      */     private static final String TYPE_DATE = "date";
/*      */     
/*      */     public DateFieldProperty(boolean store) throws JSONException {
/*  299 */       super("date", store);
/*  300 */       put("format", "yyyyMMddHHmmssSSS");
/*      */     }
/*      */   }
/*      */   
/*      */   private class StringFieldProperty extends ElasticSearchIndex.FieldProperty
/*      */   {
/*      */     private static final String TYPE_STRING = "string";
/*      */     
/*      */     public StringFieldProperty(boolean store) throws JSONException
/*      */     {
/*  310 */       super("string", store);
/*      */     }
/*      */   }
/*      */   
/*      */   public Indexer openIndexer()
/*      */   {
/*  316 */     return new ElasticSearchIndexer(null);
/*      */   }
/*      */   
/*      */   public ZimbraIndexSearcher openSearcher()
/*      */   {
/*  321 */     ElasticIndexReader reader = new ElasticIndexReader(null);
/*  322 */     return new ZimbraElasticIndexSearcher(reader);
/*      */   }
/*      */   
/*      */   public void deleteIndex()
/*      */   {
/*  327 */     HttpMethod method = new DeleteMethod(ElasticSearchConnector.actualUrl(this.indexUrl));
/*      */     try {
/*  329 */       ElasticSearchConnector connector = new ElasticSearchConnector();
/*  330 */       int statusCode = connector.executeMethod(method);
/*  331 */       if (statusCode == 200) {
/*  332 */         boolean ok = connector.getBooleanAtJsonPath(new String[] { "ok" }, false);
/*  333 */         boolean acknowledged = connector.getBooleanAtJsonPath(new String[] { "acknowledged" }, false);
/*  334 */         if ((!ok) || (!acknowledged)) {
/*  335 */           ZimbraLog.index.debug("Delete index status ok=%b acknowledged=%b", new Object[] { Boolean.valueOf(ok), Boolean.valueOf(acknowledged) });
/*      */         }
/*      */       } else {
/*  338 */         String error = connector.getStringAtJsonPath(new String[] { "error" });
/*  339 */         if ((error != null) && (error.startsWith("IndexMissingException"))) {
/*  340 */           ZimbraLog.index.debug("Unable to delete index for key=%s.  Index is missing", new Object[] { this.key });
/*      */         } else {
/*  342 */           ZimbraLog.index.error("Problem deleting index for key=%s error=%s", new Object[] { this.key, error });
/*      */         }
/*      */       }
/*      */     } catch (HttpException e) {
/*  346 */       ZimbraLog.index.error("Problem Deleting index with key=" + this.key, e);
/*      */     } catch (IOException e) {
/*  348 */       ZimbraLog.index.error("Problem Deleting index with key=" + this.key, e);
/*      */     }
/*  350 */     this.haveMappingInfo = false;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void warmup() {}
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void evict() {}
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public boolean verify(PrintStream out)
/*      */   {
/*  372 */     return true;
/*      */   }
/*      */   
/*      */   public int getDocCount() {
/*  376 */     refreshIndexIfNecessary();
/*  377 */     String url = String.format("%s%s/docs/", new Object[] { this.indexUrl, "_stats" });
/*  378 */     GetMethod method = new GetMethod(ElasticSearchConnector.actualUrl(url));
/*      */     try {
/*  380 */       ElasticSearchConnector connector = new ElasticSearchConnector();
/*  381 */       int statusCode = connector.executeMethod(method);
/*  382 */       if (statusCode == 200) {
/*  383 */         return connector.getIntAtJsonPath(new String[] { "_all", "total", "docs", "count" }, 0);
/*      */       }
/*      */     }
/*      */     catch (HttpException e) {
/*  387 */       ZimbraLog.index.error("Problem getting stats for index %s", url, e);
/*      */     } catch (IOException e) {
/*  389 */       ZimbraLog.index.error("Problem getting stats for index %s", url, e);
/*      */     }
/*  391 */     return 0;
/*      */   }
/*      */   
/*      */   public static final class Factory implements IndexStore.Factory
/*      */   {
/*      */     public Factory() {
/*  397 */       ZimbraLog.index.info("Created ElasticSearchIndex\n");
/*      */     }
/*      */     
/*      */     public ElasticSearchIndex getIndexStore(Mailbox mbox)
/*      */     {
/*  402 */       return new ElasticSearchIndex(mbox, null);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */     public void destroy() {}
/*      */     
/*      */ 
/*      */ 
/*      */     public List<String> getIndexes()
/*      */     {
/*  413 */       List<String> indexNames = Lists.newArrayList();
/*  414 */       String url = String.format("%s%s", new Object[] { LC.zimbra_index_elasticsearch_url_base.value(), "_status" });
/*  415 */       GetMethod method = new GetMethod(ElasticSearchConnector.actualUrl(url));
/*      */       try {
/*  417 */         ElasticSearchConnector connector = new ElasticSearchConnector();
/*  418 */         int statusCode = connector.executeMethod(method);
/*  419 */         if (statusCode != 200) {
/*  420 */           ZimbraLog.index.error("Problem getting list of Elastic Search indexes httpstatus=%d", new Object[] { Integer.valueOf(statusCode) });
/*      */         }
/*  422 */         JSONObject indices = connector.getObjectAtJsonPath(new String[] { "indices" });
/*  423 */         if (indices != null) {
/*  424 */           JSONArray names = indices.names();
/*  425 */           if (names != null) {
/*  426 */             for (int index = 0; index < names.length(); index++) {
/*  427 */               String name = names.optString(index);
/*  428 */               if (name != null) {
/*  429 */                 indexNames.add(name);
/*      */               }
/*      */             }
/*      */           }
/*      */         }
/*      */       } catch (HttpException e) {
/*  435 */         ZimbraLog.index.error("Problem getting list of Elastic Search indexes", e);
/*      */       } catch (IOException e) {
/*  437 */         ZimbraLog.index.error("Problem getting list of Elastic Search indexes", e);
/*      */       }
/*  439 */       return indexNames;
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   private final class ElasticSearchIndexer
/*      */     implements Indexer
/*      */   {
/*      */     private ElasticSearchIndexer() {}
/*      */     
/*      */ 
/*      */     public void close() {}
/*      */     
/*      */ 
/*      */     public void compact() {}
/*      */     
/*      */ 
/*      */     public int maxDocs()
/*      */     {
/*  459 */       return ElasticSearchIndex.this.getDocCount();
/*      */     }
/*      */     
/*      */     private String streamToString(TokenStream tokenStream) throws IOException {
/*  463 */       tokenStream.reset();
/*  464 */       List<String> toks = Lists.newArrayList();
/*  465 */       CharTermAttribute charTermAttribute = (CharTermAttribute)tokenStream.addAttribute(CharTermAttribute.class);
/*  466 */       while (tokenStream.incrementToken()) {
/*  467 */         toks.add(charTermAttribute.toString());
/*      */       }
/*  469 */       tokenStream.end();
/*  470 */       tokenStream.close();
/*  471 */       return Joiner.on(" ").join(toks);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     private boolean useZimbraAnalyzer(String fieldName)
/*      */     {
/*  480 */       LuceneFields.IndexField field = LuceneFields.IndexField.fromFieldName(fieldName);
/*  481 */       if ((field.getIndexSetting().equals(Field.Index.NOT_ANALYZED)) || (field.getIndexSetting().equals(Field.Index.NOT_ANALYZED_NO_NORMS)) || (field.getIndexSetting().equals(Field.Index.NO)))
/*      */       {
/*      */ 
/*  484 */         return false;
/*      */       }
/*  486 */       return true;
/*      */     }
/*      */     
/*      */     private String readerToTokenString(String fieldName, Reader original) throws IOException {
/*  490 */       if (useZimbraAnalyzer(fieldName)) {
/*  491 */         Analyzer analyzer = ZimbraAnalyzer.getInstance();
/*  492 */         String tokens = streamToString(analyzer.tokenStream(fieldName, original));
/*  493 */         return tokens;
/*      */       }
/*  495 */       BufferedReader bufferedReader = new BufferedReader(original);
/*  496 */       String line = null;
/*  497 */       StringBuilder sb = new StringBuilder();
/*  498 */       String ls = System.getProperty("line.separator");
/*  499 */       while ((line = bufferedReader.readLine()) != null) {
/*  500 */         sb.append(line);
/*  501 */         sb.append(ls);
/*      */       }
/*  503 */       return sb.toString();
/*      */     }
/*      */     
/*      */     private String stringToTokenString(String fieldName, String original) throws IOException
/*      */     {
/*  508 */       if (useZimbraAnalyzer(fieldName)) {
/*  509 */         Analyzer analyzer = ZimbraAnalyzer.getInstance();
/*  510 */         String tokens = streamToString(analyzer.tokenStream(fieldName, new StringReader(original)));
/*  511 */         return tokens;
/*      */       }
/*  513 */       return original;
/*      */     }
/*      */     
/*      */     private void addFieldToDocument(JSONObject jsonObj, Fieldable field) throws IOException
/*      */     {
/*      */       try {
/*  519 */         if (field.isTokenized()) {
/*  520 */           TokenStream stream = field.tokenStreamValue();
/*  521 */           if (stream != null) {
/*  522 */             String tokens = streamToString(stream);
/*  523 */             jsonObj.put(field.name(), tokens);
/*      */           } else {
/*  525 */             Reader reader = field.readerValue();
/*  526 */             if (reader != null) {
/*  527 */               jsonObj.put(field.name(), readerToTokenString(field.name(), reader));
/*      */             } else {
/*  529 */               String val = field.stringValue();
/*  530 */               if (val != null) {
/*  531 */                 jsonObj.put(field.name(), stringToTokenString(field.name(), val));
/*      */               } else {
/*  533 */                 ZimbraLog.index.debug("addFieldToDocument IGNORING tokenized field=%s", new Object[] { field.name() });
/*      */               }
/*      */             }
/*      */           }
/*      */         } else {
/*  538 */           String val = field.stringValue();
/*  539 */           if (val != null) {
/*  540 */             jsonObj.put(field.name(), stringToTokenString(field.name(), val));
/*      */           } else {
/*  542 */             ZimbraLog.index.debug("addFieldToDocument IGNORING field=%s", new Object[] { field.name() });
/*      */           }
/*      */         }
/*      */       } catch (JSONException e) {
/*  546 */         ZimbraLog.index.error("Problem creating JSON for indexing document", e);
/*      */       }
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     public void addDocument(Folder folder, MailItem item, List<IndexDocument> docs)
/*      */       throws IOException
/*      */     {
/*  558 */       if ((docs == null) || (docs.isEmpty())) {
/*  559 */         return;
/*      */       }
/*  561 */       ElasticSearchIndex.this.initializeIndex();
/*      */       
/*      */ 
/*      */ 
/*  565 */       switch (ElasticSearchIndex.1.$SwitchMap$com$zimbra$cs$mailbox$MailItem$IndexStatus[item.getIndexStatus().ordinal()]) {
/*      */       case 1: 
/*      */       case 2: 
/*  568 */         List<Integer> ids = Lists.newArrayListWithCapacity(1);
/*  569 */         ids.add(new Integer(item.getId()));
/*  570 */         deleteDocument(ids);
/*  571 */         break;
/*      */       case 3: 
/*      */         break;
/*      */       default: 
/*  575 */         if (!$assertionsDisabled) throw new AssertionError(item.getIndexId());
/*      */         break;
/*      */       }
/*  578 */       for (IndexDocument doc : docs)
/*      */       {
/*  580 */         String url = String.format("%s%s/", new Object[] { ElasticSearchIndex.this.indexUrl, "zimbra" });
/*  581 */         PostMethod method = new PostMethod(ElasticSearchConnector.actualUrl(url));
/*  582 */         JSONObject jsonObj = new JSONObject();
/*      */         
/*  584 */         synchronized (doc) {
/*  585 */           IndexStore.setFields(item, doc);
/*  586 */           Document luceneDoc = doc.toDocument();
/*  587 */           for (Fieldable field : luceneDoc.getFields()) {
/*  588 */             addFieldToDocument(jsonObj, field);
/*      */           }
/*      */         }
/*      */         try {
/*  592 */           method.setRequestEntity(new StringRequestEntity(jsonObj.toString(), "application/json", "utf-8"));
/*      */           
/*  594 */           ElasticSearchConnector connector = new ElasticSearchConnector();
/*  595 */           int statusCode = connector.executeMethod(method);
/*  596 */           if (statusCode != 201) {
/*  597 */             ZimbraLog.index.error("Problem indexing document with id=%d httpstatus=%d", new Object[] { Integer.valueOf(item.getId()), Integer.valueOf(statusCode) });
/*      */           }
/*      */         }
/*      */         catch (HttpException e) {
/*  601 */           ZimbraLog.index.error("Problem indexing document with id=%d", new Object[] { Integer.valueOf(item.getId()) });
/*      */         } catch (IOException e) {
/*  603 */           ZimbraLog.index.error("Problem indexing document with id=%d", new Object[] { Integer.valueOf(item.getId()) });
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */     public void deleteDocument(List<Integer> ids)
/*      */     {
/*  613 */       ElasticSearchIndex.this.refreshIndexIfNecessary();
/*  614 */       String url = String.format("%s%s/_query", new Object[] { ElasticSearchIndex.this.indexUrl, "zimbra" });
/*  615 */       for (Integer id : ids) {
/*  616 */         DeleteMethod method = new DeleteMethod(ElasticSearchConnector.actualUrl(url));
/*  617 */         NameValuePair[] querys = new NameValuePair[1];
/*  618 */         String query = String.format("%s:%s", new Object[] { "l.mbox_blob_id", id.toString() });
/*  619 */         querys[0] = new NameValuePair("q", query);
/*  620 */         method.setQueryString(querys);
/*      */         try {
/*  622 */           ElasticSearchConnector connector = new ElasticSearchConnector();
/*  623 */           int statusCode = connector.executeMethod(method);
/*  624 */           if (statusCode == 200) {
/*  625 */             ZimbraLog.index.debug("Deleted documents with id=%d", new Object[] { id });
/*      */           } else {
/*  627 */             ZimbraLog.index.error("Problem deleting documents with id=%d httpstatus=%d", new Object[] { id, Integer.valueOf(statusCode) });
/*      */           }
/*      */         } catch (HttpException e) {
/*  630 */           ZimbraLog.index.error("Problem deleting documents with id=%d", new Object[] { id });
/*      */         } catch (IOException e) {
/*  632 */           ZimbraLog.index.error("Problem deleting documents with id=%d", new Object[] { id });
/*      */         }
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   private final class ElasticIndexReader
/*      */     implements ZimbraIndexReader
/*      */   {
/*      */     private ElasticIndexReader() {}
/*      */     
/*      */     public void close()
/*      */       throws IOException
/*      */     {}
/*      */     
/*      */     public int numDocs()
/*      */     {
/*  649 */       return ElasticSearchIndex.this.getDocCount();
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     public int numDeletedDocs()
/*      */     {
/*  658 */       ElasticSearchIndex.this.refreshIndexIfNecessary();
/*  659 */       String url = String.format("%s%s/docs/", new Object[] { ElasticSearchIndex.this.indexUrl, "_stats" });
/*  660 */       GetMethod method = new GetMethod(ElasticSearchConnector.actualUrl(url));
/*      */       try {
/*  662 */         ElasticSearchConnector connector = new ElasticSearchConnector();
/*  663 */         int statusCode = connector.executeMethod(method);
/*  664 */         if (statusCode == 200) {
/*  665 */           return connector.getIntAtJsonPath(new String[] { "_all", "total", "docs", "deleted" }, 0);
/*      */         }
/*      */       }
/*      */       catch (HttpException e) {
/*  669 */         ZimbraLog.index.error("Problem getting stats for index %s", url, e);
/*      */       } catch (IOException e) {
/*  671 */         ZimbraLog.index.error("Problem getting stats for index %s", url, e);
/*      */       }
/*  673 */       return 0;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     public ZimbraIndexReader.TermFieldEnumeration getTermsForField(String field, String firstTermValue)
/*      */       throws IOException
/*      */     {
/*  683 */       return new ElasticSearchTermValueEnumeration(field, firstTermValue, null);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */     private final class ElasticSearchTermValueEnumeration
/*      */       implements ZimbraIndexReader.TermFieldEnumeration
/*      */     {
/*  692 */       private final Queue<BrowseTerm> termValues = Lists.newLinkedList();
/*      */       
/*  694 */       private ElasticSearchTermValueEnumeration(String field, String firstTermValue) { List<BrowseTerm> allValues = Lists.newArrayList();
/*  695 */         ElasticSearchIndex.this.refreshIndexIfNecessary();
/*  696 */         String url = String.format("%s_termlist/%s", new Object[] { ElasticSearchIndex.this.indexUrl, field });
/*  697 */         GetMethod method = new GetMethod(ElasticSearchConnector.actualUrl(url));
/*      */         try {
/*  699 */           ElasticSearchConnector connector = new ElasticSearchConnector();
/*  700 */           int statusCode = connector.executeMethod(method);
/*  701 */           if (statusCode == 200) {
/*  702 */             JSONArray terms = connector.getArrayAtJsonPath(new String[] { "terms" });
/*  703 */             if (terms != null) {
/*  704 */               for (int index = 0; index < terms.length(); index++) {
/*  705 */                 String hit = terms.optString(index);
/*  706 */                 if ((hit != null) && (hit.compareTo(firstTermValue) >= 0)) {
/*  707 */                   allValues.add(new BrowseTerm(hit, 1));
/*      */                 }
/*      */               }
/*      */             }
/*      */           }
/*      */         } catch (HttpException e) {
/*  713 */           ZimbraLog.index.error("Problem getting stats for index %s", url, e);
/*      */         } catch (IOException e) {
/*  715 */           ZimbraLog.index.error("Problem getting stats for index %s", url, e);
/*      */         }
/*  717 */         Collections.sort(allValues, new Comparator()
/*      */         {
/*      */           public int compare(BrowseTerm o1, BrowseTerm o2) {
/*  720 */             int retVal = o1.getText().compareTo(o2.getText());
/*  721 */             if (retVal == 0) {
/*  722 */               retVal = o2.getFreq() - o1.getFreq();
/*      */             }
/*  724 */             return retVal;
/*      */           }
/*  726 */         });
/*  727 */         this.termValues.addAll(allValues);
/*      */       }
/*      */       
/*      */       public boolean hasMoreElements()
/*      */       {
/*  732 */         return this.termValues.peek() != null;
/*      */       }
/*      */       
/*      */       public BrowseTerm nextElement()
/*      */       {
/*  737 */         BrowseTerm nextVal = (BrowseTerm)this.termValues.poll();
/*  738 */         if (nextVal == null) {
/*  739 */           throw new NoSuchElementException("No more values");
/*      */         }
/*  741 */         return nextVal;
/*      */       }
/*      */       
/*      */       public void close()
/*      */         throws IOException
/*      */       {}
/*      */     }
/*      */   }
/*      */   
/*      */   public boolean isPendingDelete()
/*      */   {
/*  752 */     return false;
/*      */   }
/*      */   
/*      */   public void setPendingDelete(boolean pendingDelete) {}
/*      */   
/*      */   public void optimize() {}
/*      */   
/*      */   public final class ZimbraElasticIndexSearcher implements ZimbraIndexSearcher
/*      */   {
/*      */     final ElasticSearchIndex.ElasticIndexReader reader;
/*      */     
/*      */     public ZimbraElasticIndexSearcher(ElasticSearchIndex.ElasticIndexReader reader) {
/*  764 */       this.reader = reader;
/*      */     }
/*      */     
/*      */     public void close() throws IOException
/*      */     {
/*  769 */       this.reader.close();
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */     public Document doc(ZimbraIndexDocumentID docID)
/*      */       throws IOException
/*      */     {
/*  777 */       if (docID == null) {
/*  778 */         return null;
/*      */       }
/*  780 */       if ((docID instanceof ZimbraElasticDocumentID)) {
/*  781 */         ZimbraElasticDocumentID eDocID = (ZimbraElasticDocumentID)docID;
/*  782 */         String[] storedFields = { "l.partname", "filename", "l.size", "hasAttach", "hasFlag", "priority", "l.mbox_blob_id", "l.date", "l.version" };
/*      */         
/*      */ 
/*  785 */         String url = String.format("%s%s/%s?fields=%s", new Object[] { ElasticSearchIndex.this.indexUrl, "zimbra", eDocID.getDocID(), Joiner.on(',').join(storedFields) });
/*      */         
/*  787 */         GetMethod method = new GetMethod(ElasticSearchConnector.actualUrl(url));
/*      */         try {
/*  789 */           ElasticSearchConnector connector = new ElasticSearchConnector();
/*  790 */           int statusCode = connector.executeMethod(method);
/*  791 */           if (statusCode == 200) {
/*  792 */             Document document = new Document();
/*      */             
/*      */ 
/*      */ 
/*  796 */             JSONObject body = connector.getObjectAtJsonPath(new String[] { "fields" });
/*  797 */             if (body == null) {
/*  798 */               return document;
/*      */             }
/*  800 */             Iterator iter = body.keys();
/*  801 */             while (iter.hasNext()) {
/*  802 */               String key = (String)iter.next();
/*  803 */               document.add(new Field(key, body.getString(key), Field.Store.YES, Field.Index.NO));
/*      */             }
/*  805 */             return document;
/*      */           }
/*      */         } catch (HttpException e) {
/*  808 */           ZimbraLog.index.error("Problem getting %s", url, e);
/*      */         } catch (JSONException e) {
/*  810 */           throw new IOException("Problem processing JSON representing " + url, e);
/*      */         }
/*  812 */         return null;
/*      */       }
/*  814 */       throw new IllegalArgumentException("Expected a ZimbraElasticDocumentID");
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */     public int docFreq(Term term)
/*      */       throws IOException
/*      */     {
/*      */       try
/*      */       {
/*  824 */         JSONObject jsonobj = new JSONObject();
/*  825 */         JSONObject termObj = new JSONObject();
/*  826 */         termObj.put(term.field(), term.text());
/*  827 */         jsonobj.put("term", termObj);
/*  828 */         String url = String.format("%s%s/_count", new Object[] { ElasticSearchIndex.this.indexUrl, "zimbra" });
/*  829 */         PostMethod method = new PostMethod(ElasticSearchConnector.actualUrl(url));
/*      */         try {
/*  831 */           method.setRequestEntity(new StringRequestEntity(jsonobj.toString(), "application/json", "utf-8"));
/*      */           
/*  833 */           ElasticSearchConnector connector = new ElasticSearchConnector();
/*  834 */           ElasticSearchIndex.this.refreshIndexIfNecessary();
/*  835 */           int statusCode = connector.executeMethod(method);
/*  836 */           if (statusCode == 200) {
/*  837 */             return connector.getIntAtJsonPath(new String[] { "count" }, 0);
/*      */           }
/*      */         } catch (HttpException e) {
/*  840 */           ZimbraLog.index.error("Problem with docFreq %s", url, e);
/*      */         } catch (IOException e) {
/*  842 */           ZimbraLog.index.error("Problem with docFreq %s", url, e);
/*      */         }
/*      */       } catch (JSONException e) {
/*  845 */         ZimbraLog.index.debug("ElasticSearchIndex docFreq - problem creating JSON", e);
/*  846 */         return 0;
/*      */       }
/*  848 */       return 0;
/*      */     }
/*      */     
/*      */     public ZimbraIndexReader getIndexReader()
/*      */     {
/*  853 */       return this.reader;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */     public ZimbraTopDocs search(Query query, int n)
/*      */       throws IOException
/*      */     {
/*  861 */       return search(query, null, n);
/*      */     }
/*      */     
/*      */ 
/*      */     public ZimbraTopDocs search(Query query, ZimbraTermsFilter filter, int n)
/*      */       throws IOException
/*      */     {
/*  868 */       List<ZimbraScoreDoc> scoreDocs = Lists.newArrayList();
/*  869 */       JSONObject requestJson = null;
/*      */       try {
/*  871 */         requestJson = searchQueryToJSON(query, filter, null);
/*  872 */         if (requestJson == null) {
/*  873 */           return ZimbraTopDocs.create(scoreDocs.size(), scoreDocs);
/*      */         }
/*      */       } catch (JSONException e) {
/*  876 */         ZimbraLog.index.debug("ElasticSearchIndex search - problem creating JSON for Query", e);
/*  877 */         return ZimbraTopDocs.create(scoreDocs.size(), scoreDocs);
/*      */       }
/*  879 */       if (requestJson != null)
/*      */       {
/*  881 */         String url = String.format("%s%s/_search?size=%d", new Object[] { ElasticSearchIndex.this.indexUrl, "zimbra", Integer.valueOf(n) });
/*      */         try {
/*  883 */           ElasticSearchIndex.this.refreshIndexIfNecessary();
/*      */           
/*      */ 
/*  886 */           PostMethod method = new PostMethod(ElasticSearchConnector.actualUrl(url));
/*  887 */           method.setRequestEntity(new StringRequestEntity(requestJson.toString(), "application/json", "utf-8"));
/*      */           
/*  889 */           ElasticSearchConnector connector = new ElasticSearchConnector();
/*  890 */           int statusCode = connector.executeMethod(method);
/*  891 */           if (statusCode == 200) {
/*  892 */             JSONArray hits = connector.getArrayAtJsonPath(new String[] { "hits", "hits" });
/*  893 */             if (hits != null) {
/*  894 */               for (int index = 0; index < hits.length(); index++) {
/*  895 */                 JSONObject hit = hits.optJSONObject(index);
/*  896 */                 if (hit != null) {
/*  897 */                   String id = hit.getString("_id");
/*  898 */                   if (id != null) {
/*  899 */                     scoreDocs.add(ZimbraScoreDoc.create(new ZimbraElasticDocumentID(id)));
/*      */                   }
/*      */                 }
/*      */               }
/*      */             }
/*      */           }
/*      */         } catch (HttpException e) {
/*  906 */           ZimbraLog.index.error("Problem with query against index %s", url, e);
/*      */         } catch (IOException e) {
/*  908 */           ZimbraLog.index.error("Problem with query against index %s", url, e);
/*      */         } catch (JSONException e) {
/*  910 */           ZimbraLog.index.debug("search - problem processing JSON Query response against index %s", url, e);
/*      */         }
/*      */       }
/*  913 */       return ZimbraTopDocs.create(scoreDocs.size(), scoreDocs);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */     public ZimbraTopFieldDocs search(Query query, ZimbraTermsFilter filter, int n, Sort sort)
/*      */       throws IOException
/*      */     {
/*  922 */       List<ZimbraScoreDoc> scoreDocs = Lists.newArrayList();
/*  923 */       List<SortField> sortFields = Lists.newArrayList();
/*  924 */       if (sort != null) {
/*  925 */         Collections.addAll(sortFields, sort.getSort());
/*  926 */         for (SortField sortField : sortFields) {
/*  927 */           sortField.getField();
/*      */         }
/*      */       }
/*  930 */       JSONObject requestJson = null;
/*      */       try {
/*  932 */         requestJson = searchQueryToJSON(query, filter, sortFields);
/*  933 */         if (requestJson == null) {
/*  934 */           return ZimbraTopFieldDocs.create(0, scoreDocs, sortFields);
/*      */         }
/*      */       } catch (JSONException e) {
/*  937 */         ZimbraLog.index.debug("ElasticSearchIndex search - problem creating JSON for Query", e);
/*  938 */         return ZimbraTopFieldDocs.create(0, scoreDocs, sortFields);
/*      */       }
/*  940 */       if (requestJson != null)
/*      */       {
/*  942 */         String url = String.format("%s%s/_search?size=%d", new Object[] { ElasticSearchIndex.this.indexUrl, "zimbra", Integer.valueOf(n) });
/*  943 */         ElasticSearchIndex.this.refreshIndexIfNecessary();
/*      */         
/*      */         try
/*      */         {
/*  947 */           PostMethod method = new PostMethod(ElasticSearchConnector.actualUrl(url));
/*  948 */           method.setRequestEntity(new StringRequestEntity(requestJson.toString(), "application/json", "utf-8"));
/*      */           
/*  950 */           ElasticSearchConnector connector = new ElasticSearchConnector();
/*  951 */           int statusCode = connector.executeMethod(method);
/*  952 */           if (statusCode == 200) {
/*  953 */             JSONArray hits = connector.getArrayAtJsonPath(new String[] { "hits", "hits" });
/*  954 */             if (hits != null) {
/*  955 */               for (int index = 0; index < hits.length(); index++) {
/*  956 */                 JSONObject hit = hits.optJSONObject(index);
/*  957 */                 if (hit != null) {
/*  958 */                   String id = hit.getString("_id");
/*  959 */                   if (id != null) {
/*  960 */                     scoreDocs.add(ZimbraScoreDoc.create(new ZimbraElasticDocumentID(id)));
/*      */                   }
/*      */                 }
/*      */               }
/*      */             }
/*      */           }
/*      */         } catch (HttpException e) {
/*  967 */           ZimbraLog.index.error("Problem with query against index %s", url, e);
/*      */         } catch (IOException e) {
/*  969 */           ZimbraLog.index.error("Problem with query against index %s", url, e);
/*      */         } catch (JSONException e) {
/*  971 */           ZimbraLog.index.debug("search - problem processing JSON Query response against index %s", url, e);
/*      */         }
/*      */       }
/*  974 */       return ZimbraTopFieldDocs.create(scoreDocs.size(), scoreDocs, sortFields);
/*      */     }
/*      */     
/*      */     private JSONObject TermQueryToJSON(TermQuery query) throws JSONException {
/*  978 */       Term term = query.getTerm();
/*  979 */       JSONObject queryObj = new JSONObject();
/*  980 */       JSONObject termObj = new JSONObject();
/*  981 */       termObj.put(term.field(), term.text());
/*  982 */       queryObj.put("term", termObj);
/*  983 */       return queryObj;
/*      */     }
/*      */     
/*      */     private JSONObject PrefixQueryToJSON(PrefixQuery query) throws JSONException {
/*  987 */       Term term = query.getPrefix();
/*  988 */       JSONObject queryObj = new JSONObject();
/*  989 */       JSONObject termObj = new JSONObject();
/*  990 */       termObj.put(term.field(), term.text());
/*  991 */       queryObj.put("prefix", termObj);
/*  992 */       return queryObj;
/*      */     }
/*      */     
/*      */     private JSONObject WildcardQueryToJSON(WildcardQuery query) throws JSONException {
/*  996 */       Term term = query.getTerm();
/*  997 */       JSONObject queryObj = new JSONObject();
/*  998 */       JSONObject termObj = new JSONObject();
/*  999 */       termObj.put(term.field(), term.text());
/* 1000 */       queryObj.put("wildcard", termObj);
/* 1001 */       return queryObj;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     private JSONObject TermRangeQueryToJSON(TermRangeQuery query)
/*      */       throws JSONException
/*      */     {
/* 1013 */       JSONObject queryObj = new JSONObject();
/* 1014 */       JSONObject fieldObj = new JSONObject();
/* 1015 */       JSONObject detailsObj = new JSONObject();
/* 1016 */       if (null != query.getCollator())
/*      */       {
/* 1018 */         ZimbraLog.index.error("ElasticSearchIndex does not support TermRangeQueries with collators");
/* 1019 */         return null;
/*      */       }
/* 1021 */       detailsObj.put("from", query.getLowerTerm());
/* 1022 */       detailsObj.put("to", query.getUpperTerm());
/* 1023 */       detailsObj.put("include_lower", query.includesLower());
/* 1024 */       detailsObj.put("include_upper", query.includesUpper());
/* 1025 */       detailsObj.put("boost", query.getBoost());
/* 1026 */       fieldObj.put(query.getField(), detailsObj);
/* 1027 */       queryObj.put("range", fieldObj);
/* 1028 */       return queryObj;
/*      */     }
/*      */     
/*      */     private JSONObject MultiTermQueryToJSON(MultiTermQuery query) throws JSONException {
/* 1032 */       if ((query instanceof PrefixQuery))
/* 1033 */         return PrefixQueryToJSON((PrefixQuery)query);
/* 1034 */       if ((query instanceof WildcardQuery))
/* 1035 */         return WildcardQueryToJSON((WildcardQuery)query);
/* 1036 */       if ((query instanceof TermRangeQuery)) {
/* 1037 */         return TermRangeQueryToJSON((TermRangeQuery)query);
/*      */       }
/*      */       
/* 1040 */       ZimbraLog.index.error("ElasticSearchIndex does not support search queries of type %s", new Object[] { query.getClass().getName() });
/*      */       
/*      */ 
/* 1043 */       return null;
/*      */     }
/*      */     
/*      */ 
/*      */     private JSONObject PhraseQueryToJSON(PhraseQuery query)
/*      */       throws JSONException
/*      */     {
/* 1050 */       String field = null;
/* 1051 */       List<String> words = Lists.newArrayList();
/* 1052 */       for (Term term : query.getTerms()) {
/* 1053 */         field = term.field();
/* 1054 */         words.add(term.text());
/*      */       }
/* 1056 */       JSONObject queryObj = new JSONObject();
/* 1057 */       JSONObject fieldPhraseObj = new JSONObject();
/* 1058 */       fieldPhraseObj.put(field, Joiner.on(' ').join(words));
/* 1059 */       queryObj.put("match_phrase", fieldPhraseObj);
/* 1060 */       return queryObj;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     private JSONObject MultiPhraseQueryToJSON(MultiPhraseQuery query)
/*      */       throws JSONException
/*      */     {
/* 1076 */       String field = null;
/* 1077 */       List<List<String>> phrases = Lists.newArrayList();
/* 1078 */       boolean firstWord = true;
/*      */       
/* 1080 */       for (Term[] wordsAtPos : query.getTermArrays()) {
/* 1081 */         List<List<String>> phrasesSoFar = Lists.newArrayList();
/* 1082 */         if (!firstWord) {
/* 1083 */           phrasesSoFar.addAll(phrases);
/* 1084 */           phrases = Lists.newArrayList(); }
/*      */         Term term;
/* 1086 */         for (term : wordsAtPos) {
/* 1087 */           if (firstWord) {
/* 1088 */             field = term.field();
/* 1089 */             List<String> words = Lists.newArrayList();
/* 1090 */             words.add(term.text());
/* 1091 */             phrases.add(words);
/*      */           } else {
/* 1093 */             for (List<String> phraseSoFar : phrasesSoFar) {
/* 1094 */               List<String> words = Lists.newArrayList();
/* 1095 */               words.addAll(phraseSoFar);
/* 1096 */               words.add(term.text());
/* 1097 */               phrases.add(words);
/*      */             }
/*      */           }
/*      */         }
/* 1101 */         firstWord = false;
/*      */       }
/* 1103 */       if (phrases.isEmpty()) {
/* 1104 */         return null;
/*      */       }
/* 1106 */       JSONObject queryObj = new JSONObject();
/* 1107 */       JSONObject boolObj = new JSONObject();
/* 1108 */       queryObj.put("bool", boolObj);
/* 1109 */       JSONArray shoulds = new JSONArray();
/* 1110 */       boolObj.put("should", shoulds);
/* 1111 */       boolObj.put("minimum_number_should_match", "1");
/* 1112 */       for (List<String> phrase : phrases) {
/* 1113 */         JSONObject matchPhraseObj = new JSONObject();
/* 1114 */         JSONObject fieldPhraseObj = new JSONObject();
/* 1115 */         fieldPhraseObj.put(field, Joiner.on(' ').join(phrase));
/* 1116 */         matchPhraseObj.put("match_phrase", fieldPhraseObj);
/* 1117 */         shoulds.put(matchPhraseObj);
/*      */       }
/* 1119 */       return queryObj;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     private JSONObject BooleanQueryToJSON(BooleanQuery query)
/*      */       throws JSONException
/*      */     {
/* 1132 */       JSONObject queryObj = new JSONObject();
/* 1133 */       JSONObject boolObj = null;
/* 1134 */       JSONArray musts = null;
/* 1135 */       JSONArray mustNots = null;
/* 1136 */       JSONArray shoulds = null;
/* 1137 */       for (BooleanClause clause : query) {
/* 1138 */         Query clauseQuery = clause.getQuery();
/* 1139 */         JSONObject clauseObj = QueryToJSON(clauseQuery);
/* 1140 */         if (clauseObj != null) {
/* 1141 */           BooleanClause.Occur occur = clause.getOccur();
/* 1142 */           switch (ElasticSearchIndex.1.$SwitchMap$org$apache$lucene$search$BooleanClause$Occur[occur.ordinal()]) {
/*      */           case 1: 
/* 1144 */             if (musts == null) {
/* 1145 */               musts = new JSONArray();
/*      */             }
/* 1147 */             musts.put(clauseObj);
/* 1148 */             break;
/*      */           case 2: 
/* 1150 */             if (mustNots == null) {
/* 1151 */               mustNots = new JSONArray();
/*      */             }
/* 1153 */             mustNots.put(clauseObj);
/* 1154 */             break;
/*      */           case 3: 
/* 1156 */             if (shoulds == null) {
/* 1157 */               shoulds = new JSONArray();
/*      */             }
/* 1159 */             shoulds.put(clauseObj);
/*      */           }
/*      */           
/*      */         }
/*      */       }
/* 1164 */       if ((musts != null) || (mustNots != null) || (shoulds != null)) {
/* 1165 */         boolObj = new JSONObject();
/* 1166 */         if (musts != null) {
/* 1167 */           boolObj.put("must", musts.length() == 1 ? musts.get(0) : musts);
/*      */         }
/* 1169 */         if (mustNots != null) {
/* 1170 */           boolObj.put("must_not", mustNots.length() == 1 ? mustNots.get(0) : mustNots);
/*      */         }
/* 1172 */         if (shoulds != null) {
/* 1173 */           boolObj.put("should", shoulds);
/* 1174 */           boolObj.put("should", shoulds.length() == 1 ? shoulds.get(0) : shoulds);
/*      */         }
/*      */       }
/* 1177 */       if (boolObj != null) {
/* 1178 */         queryObj.put("bool", boolObj);
/*      */       }
/* 1180 */       return queryObj;
/*      */     }
/*      */     
/*      */     private JSONObject QueryToJSON(Query query) throws JSONException {
/* 1184 */       if ((query instanceof TermQuery))
/* 1185 */         return TermQueryToJSON((TermQuery)query);
/* 1186 */       if ((query instanceof MultiTermQuery))
/* 1187 */         return MultiTermQueryToJSON((MultiTermQuery)query);
/* 1188 */       if ((query instanceof BooleanQuery))
/* 1189 */         return BooleanQueryToJSON((BooleanQuery)query);
/* 1190 */       if ((query instanceof MultiPhraseQuery))
/* 1191 */         return MultiPhraseQueryToJSON((MultiPhraseQuery)query);
/* 1192 */       if ((query instanceof PhraseQuery)) {
/* 1193 */         return PhraseQueryToJSON((PhraseQuery)query);
/*      */       }
/*      */       
/* 1196 */       ZimbraLog.index.error("ElasticSearchIndex does not support search queries of type %s", new Object[] { query.getClass().getName() });
/*      */       
/*      */ 
/* 1199 */       return null;
/*      */     }
/*      */     
/*      */ 
/*      */     private JSONObject FilterToJSON(ZimbraTermsFilter filter)
/*      */       throws JSONException
/*      */     {
/* 1206 */       if (filter == null) {
/* 1207 */         return null;
/*      */       }
/* 1209 */       JSONObject filtersO = new JSONObject();
/* 1210 */       for (Term term : filter.getTerms()) {
/* 1211 */         filtersO.accumulate(term.field(), term.text());
/*      */       }
/* 1213 */       return new JSONObject().put("terms", filtersO);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */     private JSONArray SortToJSON(List<SortField> sortFields)
/*      */       throws JSONException
/*      */     {
/* 1221 */       if ((sortFields == null) || (sortFields.isEmpty())) {
/* 1222 */         return null;
/*      */       }
/* 1224 */       JSONArray sortJson = new JSONArray();
/* 1225 */       for (SortField sortField : sortFields) {
/* 1226 */         String field = sortField.getField();
/* 1227 */         boolean reverse = sortField.getReverse();
/* 1228 */         sortJson.put(new JSONObject().put(field, new JSONObject().put("order", reverse ? "desc" : "asc")));
/*      */       }
/* 1230 */       return sortJson;
/*      */     }
/*      */     
/*      */     private JSONObject searchQueryToJSON(Query query, ZimbraTermsFilter filter, List<SortField> sortFields) throws JSONException
/*      */     {
/* 1235 */       JSONObject requestJson = null;
/* 1236 */       JSONObject queryJson = QueryToJSON(query);
/* 1237 */       if (queryJson == null) {
/* 1238 */         return null;
/*      */       }
/* 1240 */       JSONObject filterJson = FilterToJSON(filter);
/* 1241 */       if (filterJson == null) {
/* 1242 */         requestJson = new JSONObject().put("query", queryJson);
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */       }
/*      */       else
/*      */       {
/*      */ 
/*      */ 
/*      */ 
/* 1253 */         JSONObject filteredJson = new JSONObject().put("query", queryJson).put("filter", filterJson);
/* 1254 */         requestJson = new JSONObject().put("query", new JSONObject().put("filtered", filteredJson));
/*      */       }
/* 1256 */       JSONArray sortJson = SortToJSON(sortFields);
/* 1257 */       if (sortJson != null) {
/* 1258 */         requestJson.put("sort", sortJson);
/*      */       }
/* 1260 */       requestJson.put("fields", "*");
/* 1261 */       if (ZimbraLog.index.isTraceEnabled()) {
/* 1262 */         requestJson.put("explain", true);
/*      */       }
/* 1264 */       return requestJson;
/*      */     }
/*      */   }
/*      */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/index/elasticsearch/ElasticSearchIndex.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */